package ru.compft.aop.profiling;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * User: ASUS
 * Date: 21.10.12
 * Time: 11:38
 * Компонент для профилирования бизнес слоя
 */
@Component
@Aspect
public class BusinessLayerProfiler {
    private static final Logger logger = LoggerFactory.getLogger(BusinessLayerProfiler.class);

    @Before(value = "ru.compft.aop.SystemArchitecture.inBusinessLayer()")
    public void doBusinessLayerBefore() {
        System.out.println("BusinessLayerProfiler doBusinessLayerBefore");
    }

    @Before(value = "ru.compft.aop.SystemArchitecture.businessOperation()")
    public void doBusinessOperationBefore() {
        System.out.println("BusinessLayerProfiler doBusinessOperationBefore");
    }

    @Around("ru.compft.aop.SystemArchitecture.inBusinessLayer()")
    public Object doBusinessLayerProfiling(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("BusinessLayerProfiler doBusinessLayerProfiling = " + pjp);
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }

    @Around("ru.compft.aop.SystemArchitecture.businessOperation()")
    public Object doBusinessOperationProfiling(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("BusinessLayerProfiler doBusinessOperationProfiling = " + pjp);
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }

    /**
     * After (finally) advice runs however a matched method execution exits
     */
    @After("ru.compft.aop.SystemArchitecture.inBusinessLayer()")
    public void doBusinessLayerMethodAfter() {
        System.out.println("BusinessLayerProfiler doBusinessLayerMethodAfter");
    }

    @After("ru.compft.aop.SystemArchitecture.businessOperation()")
    public void doBusinessOperationMethodAfter() {
        System.out.println("BusinessLayerProfiler doBusinessOperationMethodAfter");
    }

    /**
     * Sometimes you need access in the advice body to the actual value that was returned
     *
     * @param retVal
     */
    @AfterReturning(pointcut = "ru.compft.aop.SystemArchitecture.inBusinessLayer()",
            returning = "retVal")
    public void doBusinessLayerAfterReturning(Object retVal) {
        System.out.println("BusinessLayerProfiler doBusinessLayerAfterReturning. Obj = " + retVal);
        // ...
    }

    @AfterReturning(pointcut = "ru.compft.aop.SystemArchitecture.businessOperation()",
            returning = "retVal")
    public void doBusinessOperationAfterReturning(Object retVal) {
        System.out.println("BusinessLayerProfiler doBusinessOperationAfterReturning. Obj = " + retVal);
        // ...
    }

    /**
     * After throwing advice runs when a matched method execution exits by throwing an exception
     */
    @AfterThrowing("ru.compft.aop.SystemArchitecture.inBusinessLayer()")
    public void doBusinessLayerAfterThrowing() {
        System.out.println("BusinessLayerProfiler doBusinessLayerAfterThrowing");
        // ...
    }

    @AfterThrowing("ru.compft.aop.SystemArchitecture.businessOperation()")
    public void doBusinessOperationAfterThrowing() {
        System.out.println("BusinessLayerProfiler doBusinessOperationAfterThrowing");
        // ...
    }

    /**
     * Often you want the advice to run only when exceptions of a given type are thrown, and you also often need access
     * to the thrown exception in the advice body
     *
     * @param ex
     */
    @AfterThrowing(pointcut = "ru.compft.aop.SystemArchitecture.inBusinessLayer()",
            throwing = "ex")
    public void doBusinessLayerAfterThrowing(Exception ex) {
        System.out.println("BusinessLayerProfiler doBusinessLayerAfterThrowing. Ex = " + ex);
        // ...
    }

    @AfterThrowing(pointcut = "ru.compft.aop.SystemArchitecture.businessOperation()",
            throwing = "ex")
    public void doBusinessOperationAfterThrowing(Exception ex) {
        System.out.println("BusinessLayerProfiler doBusinessOperationAfterThrowing. Ex = " + ex);
        // ...
    }
}
